package com.meilai.project.controller.web.market.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.controller.web.market.dto.*;
import com.meilai.project.controller.web.market.entity.*;
import com.meilai.project.controller.web.market.mapper.BillMarketMapper;
import com.meilai.project.controller.web.market.vo.*;
import com.meilai.project.dto.workflow.FlowBusinessDataSuperEntity;
import com.meilai.project.dto.workflow.WorkFlowCheckDTO;
import com.meilai.project.entity.business.customer.CustomerInfo;
import com.meilai.project.entity.business.sale.BillSale;
import com.meilai.project.entity.business.sale.BillSaleMediaDetail;
import com.meilai.project.entity.media.MediaPoint;
import com.meilai.project.entity.media.MediaPointChooseDaterangeMediapoint;
import com.meilai.project.entity.media.MediaType;
import com.meilai.project.exception.CommonException;
import com.meilai.project.service.business.building.BuildingAreaService;
import com.meilai.project.service.business.customer.CustomerInfoService;
import com.meilai.project.service.business.intentionScheme.IntentionSchemeService;
import com.meilai.project.service.business.intentionScheme.PointProcessService;
import com.meilai.project.service.business.media.MediaPointService;
import com.meilai.project.service.business.media.MediaTypeService;
import com.meilai.project.service.business.sale.BillSaleMediaDetailService;
import com.meilai.project.service.business.sale.BillSaleService;
import com.meilai.project.service.system.MediaTypeSpecPriceService;
import com.meilai.project.service.system.impl.UserServiceImpl;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.util.WorkFlowUtil;
import com.meilai.project.vo.business.intentionScheme.IntentionSchemeVO;
import com.meilai.project.vo.business.intentionScheme.PointProcessDateRangeVO;
import com.meilai.project.vo.business.media.MediaTypeExtVO;
import com.meilai.project.vo.business.media.MediaTypeSpecPriceVO;
import com.meilai.project.vo.business.sale.BillSaleMediaDetailVO;
import com.meilai.project.vo.business.sale.BillSaleVO;
import com.meilai.project.vo.business.sale.MediaSpecTypeCountAmountVO;
import com.meilai.project.vo.system.UserForWFVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 市场单 服务实现类
 * </p>
 *
 * @author xchen
 * @since 2022-07-16
 */
@Service
public class BillMarketServiceImpl extends ServiceImpl<BillMarketMapper, BillMarket> implements BillMarketService {

    @Autowired
    private BillMarketShootRequirementService shootRequirementService;

    @Autowired
    private BillMarketMediaTypeShootRequirementService mediaTypeShootRequirementService;

    @Autowired
    private MediaTypeService mediaTypeService;


    @Autowired
    private BillSaleService billSaleService;

    @Autowired
    private PointProcessService pointProcessService;

    @Autowired
    private BillMarketDesignPicService designPicService;

    @Autowired
    private BillMarketConfirmService billMarketConfirmService;

    @Autowired
    private BillMarketConfirmSignService confirmSignService;

    @Autowired
    private BuildingAreaService buildingAreaService;

    @Autowired
    private MediaTypeSpecPriceService mediaTypeSpecPriceService;

    @Autowired
    private MediaPointService mediaPointService;

    @Autowired
    private CustomerInfoService customerInfoService;

    @Autowired
    private BillMarketPlanService billMarketPlanService;

    @Override
    public List<BillMarketForADMakeVO> listForADMakeByContractId(Long contractId) {
        return baseMapper.listForADMakeByContractId(contractId);
    }

    @Override
    public List<BillMarketForADMakeVO> listForADMakeByCustomerId(Long customerId) {
        return baseMapper.listForADMakeByCustomerId(customerId);
    }

    @Override
    public Page<BillMarketVO> selectPageList(BillMarketListDTO searchDTO) {
        Page<BillMarketVO> page = searchDTO.createPage(BillMarketVO.class);
        List<BillMarketVO> billMarketVOS = baseMapper.selectPageList(page, searchDTO);
        List<Long> ids = billMarketVOS.stream().map(BillMarketVO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(ids)) {
            List<BillMarketDesignPic> list = designPicService.list(Wrappers.<BillMarketDesignPic>lambdaQuery().in(BillMarketDesignPic::getBill_market_id, ids));
            Map<Long, List<BillMarketDesignPic>> map = list.stream().collect(Collectors.groupingBy(BillMarketDesignPic::getBill_market_id));
            billMarketVOS.forEach(item -> {
                item.setDesignPicList(map.getOrDefault(item.getId(), new ArrayList<>()));
                if (searchDTO.getType() != null && searchDTO.getType() == 2) {
                    item.setCan_upload(item.getDesign_user_id().equals(searchDTO.getCurrentUserId()));
                }
            });
        }
        page.setRecords(billMarketVOS);
        return page;
    }


    @Override
    public BillMarketVO getOneById(Long id) {
        BillMarketVO result = baseMapper.queryDetailById(id);
        if (result == null) throw new CommonException("数据不存在！");
        if (null != id) {
            Long userId = ThreadLocalUserUtil.get().getId();
            Boolean canCheck = WorkFlowUtil.canCheckData(userId, result);
            result.setCan_check(canCheck);
            result.setIs_applyer(userId.equals(result.getFlow_applyer_id()));
        } else {
            result.setIs_applyer(true);
        }

        fillDetail(result);
        // 加入媒体类型map
        List<MediaType> list = mediaTypeService.list();
        Map<Long, String> map = list.stream().collect(Collectors.toMap(MediaType::getId, MediaType::getName));
        map.put(-1L, "全部");
        result.setTypeMap(map);
        return result;
    }

    private void fillDetail(BillMarketVO result) {
        BillSale billSale = billSaleService.getById(result.getBill_sale_id());
        List<PointProcessDateRangeVO> pointProcessDateRangeVOS = pointProcessService.queryChooseDateRangeVOList(billSale.getChoose_id());
        result.setDateRangeVOList(pointProcessDateRangeVOS);

        List<MediaSpecTypeCountAmountVO> mediaSpecTypeCountAmountVOS = billSaleService.mediaTypeCountAmount(billSale.getDaterange_id());
        result.setMediaTypeCountAmount(mediaSpecTypeCountAmountVOS);

        List<BillMarketDesignPic> billMarketDesignPics = designPicService.listByMarketId(result.getId());
        result.setDesignPicList(billMarketDesignPics);

        //构建拍摄要求返回
        Map<Long, List<BillMarketShootRequirement>> mediaType2RequireList = new HashMap<>();
        result.setMediaType2RequireList(mediaType2RequireList);
        List<BillMarketShootRequirement> billMarketShootRequirementList = shootRequirementService.listByMarketId(result.getId());
        Map<Long, BillMarketShootRequirement> requireId2Map = billMarketShootRequirementList.stream().collect(Collectors.toMap(BillMarketShootRequirement::getId, Function.identity()));

        List<BillMarketMediaTypeShootRequirement> mediaTypeShootRequirements = mediaTypeShootRequirementService.listByMarketId(result.getId());
        Map<Long, List<BillMarketMediaTypeShootRequirement>> mediaTypeId2RequireListMap = mediaTypeShootRequirements.stream().collect(Collectors.groupingBy(BillMarketMediaTypeShootRequirement::getMedia_type_id));
        for (Map.Entry<Long, List<BillMarketMediaTypeShootRequirement>> listEntry : mediaTypeId2RequireListMap.entrySet()) {
            List<BillMarketShootRequirement> itemList = new ArrayList<>();
            for (BillMarketMediaTypeShootRequirement mediaTypeShootRequirement : listEntry.getValue()) {
                BillMarketShootRequirement billMarketShootRequirement = requireId2Map.get(mediaTypeShootRequirement.getShoot_require_id());
                if (null != billMarketShootRequirement) {
                    itemList.add(billMarketShootRequirement);
                }
            }
            mediaType2RequireList.put(listEntry.getKey(), itemList);
        }
    }

    @Override
    public ConfirmBillDetail confirmBillDetail(String id) {
        List<Long> marketIdList = billMarketConfirmService.queryMarketIdListByConfirmBatch(id);
        ConfirmBillDetail confirmBillDetail = new ConfirmBillDetail();
        if (CollUtil.isEmpty(marketIdList)) {
            return confirmBillDetail;
        }
        List<BillMarketVO> billMarketVOList = new ArrayList<>();
        for (Long marketId : marketIdList) {
            BillMarketVO result = baseMapper.queryDetailById(marketId);
            if (null == result) {
                continue;
            }
            fillDetail(result);
            billMarketVOList.add(result);
        }
        if (CollUtil.isEmpty(billMarketVOList)) {
            return confirmBillDetail;
        }

        BeanUtils.copyProperties(billMarketVOList.get(0), confirmBillDetail);

        //合并MediaTypeCountAmount
        Map<String, MediaSpecTypeCountAmountVO> mediaSpecTypeCountAmountVOMap = new HashMap<>();
        for (int i = 0; i < billMarketVOList.size(); i++) {
            List<MediaSpecTypeCountAmountVO> mediaTypeCountAmounts = billMarketVOList.get(i).getMediaTypeCountAmount();
            for (MediaSpecTypeCountAmountVO mediaTypeCountAmount : mediaTypeCountAmounts) {
                String groupKey = mediaTypeCountAmount.groupKey();
                if (mediaSpecTypeCountAmountVOMap.containsKey(groupKey)) {
                    MediaSpecTypeCountAmountVO mediaSpecTypeCountAmountVO = mediaSpecTypeCountAmountVOMap.get(groupKey);
                    mediaSpecTypeCountAmountVO.setSpec_count(mediaSpecTypeCountAmountVO.getSpec_count() + mediaTypeCountAmount.getSpec_count());
                    mediaSpecTypeCountAmountVO.setAmount(mediaSpecTypeCountAmountVO.getAmount().add(mediaTypeCountAmount.getAmount()));
                } else {
                    mediaSpecTypeCountAmountVOMap.put(groupKey, mediaTypeCountAmount);
                }
            }
        }

        confirmBillDetail.setMediaTypeCountAmount(new ArrayList<>(mediaSpecTypeCountAmountVOMap.values()));
        confirmBillDetail.setBillMarketVOList(billMarketVOList);

        // 前端组件需要初始化数据 这里不能登录 所以从后台拿到数据返回给前端
        List<MediaTypeSpecPriceVO> mediaTypeSpecPriceVOS = mediaTypeSpecPriceService.allList();
        List<MediaTypeExtVO> mediaTypeExtVOS = buildingAreaService.listMediaTypes();
        confirmBillDetail.setMediaTypeExtVOList(mediaTypeExtVOS);
        confirmBillDetail.setMediaTypeSpecPriceVOList(mediaTypeSpecPriceVOS);
        return confirmBillDetail;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmShootRequirement(Long id) {
        LambdaUpdateWrapper<BillMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BillMarket::getId, id);
        updateWrapper.set(BillMarket::getShoot_requirement_confirmed, true);
        update(updateWrapper);
        //生成中间监播工单
        List<BillMarketShootRequirement> billMarketShootRequirementList = shootRequirementService.listByMarketId(id);
        Map<LocalDate, List<BillMarketShootRequirement>> dateListMap = billMarketShootRequirementList.stream().filter(item -> item.getShoot_type() == 3).collect(Collectors.groupingBy(BillMarketShootRequirement::getShoot_date));
        if (CollUtil.isEmpty(dateListMap)) {
            return;
        }
        //生成工单
        BillMarket billMarket = getById(id);
        BillSaleVO saleVO = billSaleService.getOneById(billMarket.getBill_sale_id());
        Long choose_id = saleVO.getChoose_id();
        List<MediaPointChooseDaterangeMediapoint> mediaPointChooseDaterangeMediapoints = pointProcessService.listByChooseId(choose_id);
        List<Long> mediaPointIdList = mediaPointChooseDaterangeMediapoints.stream().map(MediaPointChooseDaterangeMediapoint::getMedia_point_id).collect(Collectors.toList());
        List<MediaPoint> mediaPoints = mediaPointService.listByIds(mediaPointIdList);
        List<Long> buildingAreaIdList = mediaPoints.stream().map(MediaPoint::getBuilding_area_id).distinct().collect(Collectors.toList());

        for (Map.Entry<LocalDate, List<BillMarketShootRequirement>> localDateListEntry : dateListMap.entrySet()) {
            LocalDate date = localDateListEntry.getKey();
            List<Long> requireIdList = localDateListEntry.getValue().stream().map(BillMarketShootRequirement::getId).collect(Collectors.toList());
            pointProcessService.newMonitorWorkOrder(saleVO, buildingAreaIdList, date.plusDays(1), requireIdList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyShootRequirement(ShootRequirementDTO req) {
        // todo 新增可修改指派的设计人员
        this.update(Wrappers.<BillMarket>lambdaUpdate().set(BillMarket::getDesign_user_id, req.getDesign_user_id()).eq(BillMarket::getId, req.getId()));
        modifyShootRequirement(req.getId(), req.getMediaType2RequireList());
    }

    @Override
    public void uploadDesignPic(BillMarketDesignPicDto req) {
        List<BillMarketDesignPic> list = new ArrayList<>();
        for (String picUrl : req.getPic_url_list()) {
            BillMarketDesignPic item = new BillMarketDesignPic();
            item.setPic_url(picUrl);
            item.setBill_market_id(req.getBill_market_id());
            list.add(item);
        }
        designPicService.deleteByMarketId(req.getBill_market_id());
        designPicService.saveBatch(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String generateConfirmBill(GenerateConfirmBillDto req) {
        List<Long> billMarketIdList = req.getBillMarketIdList();
        List<BillMarket> billMarkets = listByIds(billMarketIdList);
        long count = billMarkets.stream().map(BillMarket::getContract_id).distinct().count();
        if (count > 1) {
            throw new CommonException("只能选择统一合同下的市场单！");
        }
        String batchStr = IdUtil.fastSimpleUUID();
        List<BillMarketConfirm> billMarketConfirms = new ArrayList<>();
        for (Long marketId : billMarketIdList) {
            BillMarketConfirm item = new BillMarketConfirm();
            item.setBill_market_id(marketId);
            item.setBatch_id(batchStr);
            billMarketConfirms.add(item);
        }
        //标记已生成外链
        LambdaUpdateWrapper<BillMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(BillMarket::getId, billMarketIdList);
        updateWrapper.set(BillMarket::getGenerate_link, true);
        updateWrapper.set(BillMarket::getConfirm_batch, batchStr);
        update(updateWrapper);

        billMarketConfirmService.saveBatch(billMarketConfirms);
        return batchStr;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void signConfirmBill(SignConfirmBillDTO dto) {
        BillMarketConfirmSign sign = new BillMarketConfirmSign();
        sign.setSign_img_url(dto.getSignImgUrl());
        sign.setBatch_id(dto.getBatchStr());
        confirmSignService.save(sign);

        LambdaUpdateWrapper<BillMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BillMarket::getConfirm_batch, dto.getBatchStr());
        updateWrapper.set(BillMarket::getConfirm_sign_img, dto.getSignImgUrl());
        update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(BillMarketDTO dto) {
        int flowResult = saveAndBegin(dto, true);
        if (flowResult != 1) throw new CommonException("保存至草稿箱失败，请联系管理员！");
        else return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean begin(BillMarketDTO dto) {
        // 提交
        int flowResult = saveAndBegin(dto, false);
        if (flowResult == 1) {
            // 仍在流程中
            return true;
        } else if (flowResult == 2) {
            // 无审批节点，直接结束
            endProcess(dto.getId(),true);
            return true;
        } else {
            throw new CommonException("提交失败，请联系管理员！");
        }
    }

    private void modifyShootRequirement(Long billMarketId, Map<Long, List<BillMarketShootRequirement>> mediaType2RequireList) {
        shootRequirementService.deleteByMarketId(billMarketId);
        mediaTypeShootRequirementService.deleteByMarketId(billMarketId);
        List<BillMarketMediaTypeShootRequirement> mediaTypeShootRequirements = new ArrayList<>();
        for (Map.Entry<Long, List<BillMarketShootRequirement>> listEntry : mediaType2RequireList.entrySet()) {
            List<BillMarketShootRequirement> billMarketShootRequirementList = listEntry.getValue();
            billMarketShootRequirementList.forEach(item -> item.setBill_market_id(billMarketId));
            shootRequirementService.saveBatch(billMarketShootRequirementList);
            for (BillMarketShootRequirement billMarketShootRequirement : billMarketShootRequirementList) {
                BillMarketMediaTypeShootRequirement mediaTypeShootRequirement = new BillMarketMediaTypeShootRequirement();
                mediaTypeShootRequirement.setMedia_type_id(listEntry.getKey());
                mediaTypeShootRequirement.setShoot_require_id(billMarketShootRequirement.getId());
                mediaTypeShootRequirement.setBill_market_id(billMarketId);
                mediaTypeShootRequirements.add(mediaTypeShootRequirement);
            }
        }

        mediaTypeShootRequirementService.saveBatch(mediaTypeShootRequirements);
    }

    private void modifyBillMarketPlan(Long billMarketId, List<BillMarketPlan> billMarketPlans) {
        billMarketPlanService.deleteByMarketId(billMarketId);
        billMarketPlans.forEach(item -> item.setBill_market_id(billMarketId));
        billMarketPlanService.saveBatch(billMarketPlans);
    }

    public int saveAndBegin(BillMarketDTO dto, boolean isSave) {
        // 获取当前人的id和部门id
        UserForWFVO user = UserServiceImpl.getUserForWF(dto);
        BillMarket temp = new BillMarket();
        BeanUtils.copyProperties(dto, temp);
        BillSale billSale = billSaleService.getById(dto.getBill_sale_id());
        if (billSale.getFlow_status() != 3 && billSale.getFlow_status() != 4) {
            throw new CommonException("请先将关联的销售单提交到流程中");
        }
        CustomerInfo customerInfo = customerInfoService.getById(dto.getCustomer_id());
        // 设置流程字段，flow_type请自行对应“dict_flow_type”表中的id， 比如当前入职流程（考察登记流程）的id是5
        String flow_title = "市场单申请-" + customerInfo.getName(); // 审批流程的名称，需要根据实际业务自行确定
        FlowBusinessDataSuperEntity fbdse = WorkFlowUtil.getStartSuperDataEntity(
                user.getUser_id(),  // 当前用户id
                user.getDep_id(), // 提交的部门id
                20, // 流程类型id，“dict_flow_type”表中的id
                flow_title // 自定义的流程标题
        );
        BeanUtils.copyProperties(fbdse, temp);
        // 是否为新数据
        // 新数据时，前端不传业务数据id
        // 非新数据时，即来源是“草稿箱”、“已删除”、“被退回”时，前端需要传入业务数据id
        boolean isFirst = (dto.getId() == null);

        // 由于流程字段含有id，会覆盖数据，此处需要手动setId
        if (!isFirst) temp.setId(dto.getId());

        // 新增或更新业务数据
        boolean flag = isFirst ? save(temp) : updateById(temp);
        if (!flag) throw new CommonException("保存失败");

        Long billMarketId = temp.getId();

        modifyShootRequirement(billMarketId, dto.getMediaType2RequireList());
        //modifyBillMarketPlan(billMarketId, dto.getBillMarketPlans());

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<BillMarket, BillMarketMapper>(billMarketId, user.getUser_id(), BillMarket.class);

        // 审批流程id
        // 新数据,传0L
        // 非新数据,根据数据id,查找wfData_id
        Long wfData_id = isFirst ? 0L : wfu.getWfDataId(dto.getId());
        // 旧数据记录留存
        BillMarket old_data = isFirst ? new BillMarket() : temp;

        return isSave ? wfu.SaveDraft(wfData_id) : wfu.Begin(wfData_id, "", old_data);
    }

    // 通过 和 驳回 抽出相同代码
    private int passAndBack(BillMarketCheckDTO dto, boolean isPass, boolean... updateData) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 若业务数据有审批中可修改的内容，请自行更新
        if (updateData != null && updateData[0]) {
            BillMarket updateTemp = new BillMarket();
            BeanUtils.copyProperties(dto, updateTemp);
            updateById(updateTemp);
        }

        // 业务数据
        BillMarket temp = getById(dto.getId());

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<BillMarket, BillMarketMapper>(dto.getId(), userId, BillMarket.class);

        // 审批入参类
        WorkFlowCheckDTO checkDTO = WorkFlowCheckDTO.getWorkFlowCheckDTO(temp.getFlow_current_node_id(), // 当前节点id
                temp.getFlow_json(), // 流程json
                dto.getWf_check_opinion(), // 审批意见
                dto.getWf_check_sign_url(), // 审批签名链接
                JSONObject.toJSONString(temp) // 旧数据留存
        );

        // 审批
        return isPass ? wfu.ToNext(checkDTO) : wfu.ReturnBack(checkDTO);
    }

    // 通过 和 驳回 抽出相同代码
    private int passAndBack(boolean isLinkDataOk, BillMarketCheckDTO dto, boolean isPass, boolean... updateData) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 若业务数据有审批中可修改的内容，请自行更新
        if (updateData != null && updateData[0]) {
            BillMarket updateTemp = new BillMarket();
            BeanUtils.copyProperties(dto, updateTemp);
            updateById(updateTemp);
        }

        // 业务数据
        BillMarket temp = getById(dto.getId());

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<BillMarket, BillMarketMapper>(dto.getId(), userId, BillMarket.class);

        // 审批入参类
        WorkFlowCheckDTO checkDTO = WorkFlowCheckDTO.getWorkFlowCheckDTO(temp.getFlow_current_node_id(), // 当前节点id
                temp.getFlow_json(), // 流程json
                dto.getWf_check_opinion(), // 审批意见
                dto.getWf_check_sign_url(), // 审批签名链接
                JSONObject.toJSONString(temp) // 旧数据留存
        );

        // 审批
        return isPass ? wfu.ToNext(checkDTO, isLinkDataOk) : wfu.ReturnBack(checkDTO);
    }

    // 删除 和 彻底删除 抽出相同代码
    private int deleteAndActualDel(Long id, boolean isActual) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<BillMarket, BillMarketMapper>(id, userId, BillMarket.class);

        // 流程id
        Long wfData_id = wfu.getWfDataId(id);

        return isActual ? wfu.ActualDelete(wfData_id) : wfu.Delete(wfData_id);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean pass(BillMarketCheckDTO dto) {
        // todo 增加前置条件 检查关联的销售单是否审核通过
        BillMarket market = this.getById(dto.getId());
        if (market == null) {
            throw new CommonException("市场单不存在");
        }
        BillSale billSale = billSaleService.getById(market.getBill_sale_id());
        if (billSale == null) {
            throw new CommonException("销售单不存在");
        }
        // 通过
        int flowResult = passAndBack(billSale.getFlow_status() != 4, dto, true, false);
        if (flowResult == -1){
            throw new CommonException("关联的销售单未通过审核，请先将关联的销售单关联通过");
        }else if (flowResult == 1) {
            // 通过后仍然在流程中
            return true;
        } else if (flowResult == 2) {
            // 审核后流程结束
            // 更新roster表
            endProcess(dto.getId(), true);
            return true;
        } else {
            throw new CommonException("通过失败，请联系管理员！");
        }
    }

    public void endProcess(Long id) {

    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean returnBack(BillMarketCheckDTO dto) {
        // 驳回
        int flowResult = passAndBack(dto, false, false);
        if (flowResult != 1) throw new CommonException("驳回失败，请联系管理员！");
        return true;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean delete(Long id) {
        int flowResult = deleteAndActualDel(id, false);
        if (flowResult != 1) throw new CommonException("删除失败，请联系管理员！");
        return true;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean actualDelete(Long id) {
        int flowResult = deleteAndActualDel(id, true);
        if (flowResult != 1) throw new CommonException("彻底删除失败，请联系管理员！");
        return true;
    }

    /*===============================NEW==============================*/

    @Autowired
    private BillMarketDetailService billMarketDetailService;

    @Autowired
    private BillMarketDetailShootRequirementService billMarketDetailShootRequirementService;

    @Autowired
    private BillSaleMediaDetailService billSaleMediaDetailService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(MarketBillDTO dto) {
        int flowResult = saveAndBegin(dto, true);
        if (flowResult != 1) throw new CommonException("保存至草稿箱失败，请联系管理员！");
        else return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean begin(MarketBillDTO dto) {
        // 提交
        int flowResult = saveAndBegin(dto, false);
        if (flowResult == 1) {
            // 仍在流程中
            return true;
        } else if (flowResult == 2) {
            // 无审批节点，直接结束
            endProcess(dto.getId(), true);
            return true;
        } else {
            throw new CommonException("提交失败，请联系管理员！");
        }
    }

    public int saveAndBegin(MarketBillDTO dto, boolean isSave) {
        // 获取当前人的id和部门id
        UserForWFVO user = UserServiceImpl.getUserForWF(dto);
        BillMarket temp = new BillMarket();
        BeanUtils.copyProperties(dto, temp);
        BillSale billSale = billSaleService.getById(dto.getBill_sale_id());
        if (billSale.getFlow_status() != 3 && billSale.getFlow_status() != 4) {
            throw new CommonException("请先将关联的销售单提交到流程中");
        }
        CustomerInfo customerInfo = customerInfoService.getById(dto.getCustomer_id());
        // 设置流程字段，flow_type请自行对应“dict_flow_type”表中的id， 比如当前入职流程（考察登记流程）的id是5
        String flow_title = "市场单申请-" + customerInfo.getName(); // 审批流程的名称，需要根据实际业务自行确定
        FlowBusinessDataSuperEntity fbdse = WorkFlowUtil.getStartSuperDataEntity(
                user.getUser_id(),  // 当前用户id
                user.getDep_id(), // 提交的部门id
                20, // 流程类型id，“dict_flow_type”表中的id
                flow_title // 自定义的流程标题
        );
        BeanUtils.copyProperties(fbdse, temp);
        // 是否为新数据
        // 新数据时，前端不传业务数据id
        // 非新数据时，即来源是“草稿箱”、“已删除”、“被退回”时，前端需要传入业务数据id
        boolean isFirst = (dto.getId() == null);

        // 由于流程字段含有id，会覆盖数据，此处需要手动setId
        if (!isFirst) temp.setId(dto.getId());

        // 新增或更新业务数据
        boolean flag = isFirst ? save(temp) : updateById(temp);
        if (!flag) throw new CommonException("保存失败");

        Long billMarketId = temp.getId();

        // modifyShootRequirement(billMarketId, dto.getMediaType2RequireList());
        // modifyBillMarketPlan(billMarketId, dto.getBillMarketPlans());
        modifyBillMarketDetailAndShootRequirement(billMarketId, dto.getBillMarketDetailList());
        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<BillMarket, BillMarketMapper>(billMarketId, user.getUser_id(), BillMarket.class);
        // 审批流程id
        // 新数据,传0L
        // 非新数据,根据数据id,查找wfData_id
        Long wfData_id = isFirst ? 0L : wfu.getWfDataId(dto.getId());
        // 旧数据记录留存
        BillMarket old_data = isFirst ? new BillMarket() : temp;

        return isSave ? wfu.SaveDraft(wfData_id) : wfu.Begin(wfData_id, "", old_data);
    }


    /**
     * 修改市场单详情和拍照要求
     * @param billMarketId
     * @param billMarketDetailList
     */
    private void modifyBillMarketDetailAndShootRequirement(Long billMarketId, List<BillMarketDetailVO> billMarketDetailList) {

        billMarketDetailService.deleteByMarketId(billMarketId);
        billMarketDetailShootRequirementService.deleteByMarketId(billMarketId);
        //
        for (BillMarketDetailVO billMarketDetailVO : billMarketDetailList){
            BillMarketDetail billMarketDetail = new BillMarketDetail();
            BeanUtils.copyProperties(billMarketDetailVO, billMarketDetail);
            billMarketDetail.setBill_market_id(billMarketId);
            Long billMarketDetailId = billMarketDetailService.insert(billMarketDetail);
            // 更新
            billSaleMediaDetailService.updateIsMarket(billMarketDetailId,billMarketDetail.getBill_sale_detail_id());
            // 获取当前拍照要求
            List<BillMarketDetailShootRequirement> shootRequirementList = billMarketDetailVO.getShootRequirementList();
            shootRequirementList.forEach(item -> {
                item.setBill_market_id(billMarketId);
                item.setBill_market_detail_id( billMarketDetailId );
            });
            billMarketDetailShootRequirementService.saveBatch(shootRequirementList);
        }
    }

    private void fillDetail(MarketBillVO result) {
        // 销售单
        BillSale billSale = billSaleService.getById(result.getBill_sale_id());
        if (billSale == null) throw new CommonException("销售单数据有误！");

        List<PointProcessDateRangeVO> pointProcessDateRangeVOS = pointProcessService.queryChooseDateRangeVOList(billSale.getChoose_id());
        result.setDateRangeVOList(pointProcessDateRangeVOS);

        List<BillMarketDesignPic> billMarketDesignPics = designPicService.listByMarketId(result.getId());
        result.setDesignPicList(billMarketDesignPics);
        // 获取详情LIST
        List<BillMarketDetailVO> billMarketDetailList = billMarketDetailService.listByMarketId(result.getId());
        if (billMarketDetailList.size() > 0){
            billMarketDetailList.forEach(item -> {
                item.setDuration(new String[]{item.getExecute_time_start().toString(),item.getExecute_time_end().toString()});
                // 拍照要求
                List<BillMarketDetailShootRequirement> shootRequirementList = billMarketDetailShootRequirementService.listByMarketId(result.getId(), item.getId());
                if( shootRequirementList.size() > 0){
                    item.setShootRequirementList( shootRequirementList );
                }
            });
            result.setBillMarketDetailList( billMarketDetailList);
        }
    }

    @Override
    public MarketBillVO getSingleOneById(Long id) {
        MarketBillVO result = baseMapper.querySingleById(id);
        if (result == null) throw new CommonException("数据不存在！");
        if (null != id) {
            Long userId = ThreadLocalUserUtil.get().getId();
            Boolean canCheck = WorkFlowUtil.canCheckData(userId, result);
            result.setCan_check(canCheck);
            result.setIs_applier(userId.equals(result.getFlow_applyer_id()));
        } else {
            result.setIs_applier(true);
        }
        fillDetail(result);
        return result;
    }

    @Override
    public MarketBillVO getSubOneByDetailId(Long marketDetailId) {
        MarketBillVO result = baseMapper.querySubByDetailId(marketDetailId);
        if (result == null) throw new CommonException("数据不存在！");
        if (null != marketDetailId) {
            Long userId = ThreadLocalUserUtil.get().getId();
            Boolean canCheck = WorkFlowUtil.canCheckData(userId, result);
            result.setCan_check(canCheck);
            result.setIs_applier(userId.equals(result.getFlow_applyer_id()));
        } else {
            result.setIs_applier(true);
        }
        fillDetail(result);
        return result;
    }

    @Override
    public Page<MarketBillVO> queryPageList(BillMarketListDTO searchDTO) {
        Page<MarketBillVO> page = searchDTO.createPage(MarketBillVO.class);
        List<MarketBillVO> billMarketVOS = baseMapper.queryPageList(page, searchDTO);
        List<Long> ids = billMarketVOS.stream().map(MarketBillVO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(ids)) {
            List<BillMarketDesignPic> list = designPicService.list(Wrappers.<BillMarketDesignPic>lambdaQuery().in(BillMarketDesignPic::getBill_market_id, ids));
            Map<Long, List<BillMarketDesignPic>> map = list.stream().collect(Collectors.groupingBy(BillMarketDesignPic::getBill_market_id));
            billMarketVOS.forEach(item -> {
                item.setDesignPicList(map.getOrDefault(item.getId(), new ArrayList<>()));
                if (searchDTO.getType() != null && searchDTO.getType() == 2) {
                    item.setCan_upload(item.getDesign_user_id().equals(searchDTO.getCurrentUserId()));
                }
            });
        }
        page.setRecords(billMarketVOS);
        return page;
    }

    private void initDetail(MarketBillVO result,Long saleBillDetailId) {
        // 销售单
        BillSale billSale = billSaleService.getById(result.getBill_sale_id());
        if (billSale == null) throw new CommonException("销售单数据有误！");
        result.setDept_id(billSale.getDept_id());
        result.setContract_id(billSale.getContract_id());
        result.setCustomer_id(billSale.getCustomer_id());
        result.setContract_num(billSale.getContract_num());
        //
        List<BillMarketDetailVO> billMarketDetailList = new ArrayList<BillMarketDetailVO>();
        List<BillSaleMediaDetailVO> billSaleMediaDetailList = new ArrayList<BillSaleMediaDetailVO>();
        if (saleBillDetailId != null){
            billSaleMediaDetailList = billSaleMediaDetailService.getByBillSaleId(result.getBill_sale_id(),saleBillDetailId);
        } else {
            billSaleMediaDetailList = billSaleMediaDetailService.selectByBillSaleId(result.getBill_sale_id());
        }
        if (billSaleMediaDetailList.size() > 0){
            billSaleMediaDetailList.forEach(item -> {
                BillMarketDetailVO billMarketDetailVO = new BillMarketDetailVO();
                BeanUtils.copyProperties(item,billMarketDetailVO);
                billMarketDetailList.add( billMarketDetailVO );
            });
            result.setBillMarketDetailList( billMarketDetailList);
        }
    }

    @Override
    public MarketBillVO initSingleOneById(Long saleBillId, Long saleBillDetailId) {
        MarketBillVO result = new MarketBillVO();
        result.setBill_sale_id(saleBillId);
        initDetail(result,saleBillDetailId);
        return result;
    }

    @Autowired
    private PointProcessService processService;
    @Autowired
    private IntentionSchemeService intentionSchemeService;
    public void endProcess(Long id,boolean isNew) {
        MarketBillVO marketBillVO = getSingleOneById(id);
        List<BillMarketDetailVO> detailList = marketBillVO.getBillMarketDetailList();
        if (detailList != null && detailList.size() > 0){
            detailList.forEach(item -> {
                Long choose_id = item.getChoose_id();
                List<MediaPointChooseDaterangeMediapoint> mediaPointChooseDaterangeMediapoints = processService.listByChooseId(choose_id);
                List<Long> mediaPointIdList = mediaPointChooseDaterangeMediapoints.stream().map(MediaPointChooseDaterangeMediapoint::getMedia_point_id).collect(Collectors.toList());
                if (mediaPointIdList.size() > 0){
                    List<MediaPoint> mediaPoints = mediaPointService.listByIds(mediaPointIdList);
                    List<Long> buildingAreaIdList = mediaPoints.stream().map(MediaPoint::getBuilding_area_id).distinct().collect(Collectors.toList());
                    Long intention_scheme_id = item.getIntention_scheme_id();
                    IntentionSchemeVO schemeVO = intentionSchemeService.getOneById(intention_scheme_id);
                    // 来自市场单的锁位，是变更类型
                    if (schemeVO.getRelated_type() == 2) {

                    }else {
                        // 市场单是换画类型，则生成换画工单
                        if (marketBillVO.getType() == 2){
                            processService.newReplaceWorkOrder(item, buildingAreaIdList);
                        }else {
                            processService.newUpWorkOrder(item, buildingAreaIdList);
                            processService.newDownWorkOrder(item, buildingAreaIdList);
                        }
                    }
                }
            });
        }

    }

}
